package com.caishi.lkx.user.api;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.caishi.lkx.common.AdminBaseApi;
import com.caishi.lkx.common.role.Role;
import com.caishi.lkx.common.role.Roles;
import com.caishi.lkx.common.util.ExcelUtil;
import com.caishi.lkx.user.model.DepartmentModel;
import com.caishi.lkx.user.service.IDepartmentService;
import com.caishi.lkx.user.service.IGroupService;
import com.zzw.common.Wrappers;
import com.zzw.common.exception.BizRuntimeException;
import com.zzw.common.file.OssPlugins;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author by keray
 * date:2021/4/28 3:19 下午
 */
@Tag(name = "机构组织相关")
@RestController
@RequestMapping("/user/sys/department")
public class DepartmentApi extends AdminBaseApi<IDepartmentService, DepartmentModel, Long> {

    @Resource
    private IDepartmentService departmentService;
    @Resource
    private IGroupService groupService;
    @Resource
    private OssPlugins ossPlugins;

    @Override
    public IDepartmentService loadService() {
        return departmentService;
    }


    @Operation(summary = "通过机构id获取学校学科")
    @GetMapping("/getFirstStageByGroupId")
    public Collection<DepartmentModel> getFirstStage(
            @ModelAttribute DepartmentModel searchModel,
            @RequestParam(defaultValue = "false") Boolean searchCount) {
        List<DepartmentModel> collect =
                departmentService
                        .selectList(Wrappers.lambdaQuery(searchModel.clearEmptyStringField()))
                        .parallelStream()
                        .filter(v -> v.getParentId() == null)
                        .collect(Collectors.toList());
        for (DepartmentModel departmentModel : collect) {
            departmentModel.setChildren(departmentService.selectNextChildren(departmentModel.getId()));
        }
        return collect;
    }

    @DeleteMapping("/delete")
    public Boolean delete(@RequestParam Long id) {
        List<Long> childrenIds = departmentService.allChildrenIds(id);
        if(!childrenIds.isEmpty()){
            childrenIds.add(id);
            return loadService().delete(childrenIds);
        }
        return loadService().delete(id);
    }

    @Operation(summary = "获取子学科")
    @GetMapping("/getChildren")
    public Collection<DepartmentModel> getChildren(@ModelAttribute DepartmentModel searchModel) {
        List<DepartmentModel> examChaptersModels =
                departmentService.selectNextChildren(searchModel.getId());
        for (DepartmentModel departmentModel : examChaptersModels) {
            departmentModel.setChildren(departmentService.selectNextChildren(departmentModel.getId()));
        }
        return examChaptersModels;
    }

    @Override
    protected LambdaQueryWrapper<DepartmentModel> baseWrapper(DepartmentModel model, JSONObject otherParam) {
        return super.baseWrapper(model.clearEmptyStringField("name"), null)
                .isNull(DepartmentModel::getParentId)
                .like(StrUtil.isNotBlank(model.getName()), DepartmentModel::getName, model.getName());
    }

    @Override
    protected List<DepartmentModel> listCover(List<DepartmentModel> result, JSONObject otherParam) {
        return result.parallelStream().peek(r -> {
            if (null != r.getGroupId()) {
                r.setGroupName(groupService.queryName(r.getGroupId()));
            }
            r.setChildren(departmentService.selectNextChildren(r.getId()));
        }).collect(Collectors.toList());
    }


    @Operation(summary = "前台新增组织")
    @PostMapping("/saveDepartment")
    public DepartmentModel saveDepartment(DepartmentModel departmentModel) {
        if (StrUtil.isBlank(departmentModel.getName())) {
            throw new BizRuntimeException("参数错误");
        }
        Long id = userContext.currentGroupId();
        if (null == id) {
            throw new BizRuntimeException("机构不存在");
        }
        Long parentId = departmentModel.getParentId();
        if (parentId != null) {
            Long aLong = loadService().selectCount(Wrappers.<DepartmentModel>lambdaQuery()
                    .eq(DepartmentModel::getGroupId, id)
                    .eq(DepartmentModel::getId, parentId)
            );
            if (aLong == 0) {
                throw new BizRuntimeException("父组织不存在");
            }
        }
        departmentModel.setGroupId(id);
        return loadService().insert(departmentModel);

    }

    @Operation(summary = "前台获取组织列表")
    @GetMapping("/client-list")
    public IPage<DepartmentModel> clientList(@ModelAttribute Page<DepartmentModel> page, @ModelAttribute DepartmentModel model, @NotNull JSONObject otherParam) {
        Long groupId = userContext.currentGroupId();
        IPage<DepartmentModel> data = loadService().page(loadService().pageProcessing(page), baseWrapper(model, otherParam).eq(DepartmentModel::getGroupId, groupId));
        data.setRecords(listCover(data.getRecords(), otherParam));
        return data;
    }

    @Operation(summary = "批量上传组织")
    @PostMapping("/import-department")
    @Roles({ Role.admin})
    public Boolean importDepartment(@RequestParam("file") MultipartFile file) throws IOException {
        Long groupId = userContext.currentGroupId();
        return departmentService.importDepartment(file, groupId, userContext.currentUserId());
    }

    @Operation(summary = "导出组织code")
    @GetMapping("/export-department")
    @Roles({ Role.admin})
    public String exportDepartmentCode() throws IOException {
        Long groupId = userContext.currentGroupId();
        List<DepartmentModel> departmentModels = departmentService.selectList(Wrappers.<DepartmentModel>lambdaQuery().eq(DepartmentModel::getGroupId, groupId).isNull(DepartmentModel::getParentId).select(DepartmentModel::getParentId, DepartmentModel::getId, DepartmentModel::getName));
        List<Long> id = departmentModels.parallelStream().map(DepartmentModel::getId).toList();
        departmentModels.addAll(departmentService.selectList(Wrappers.<DepartmentModel>lambdaQuery().in(DepartmentModel::getParentId, id)));
        List<Map<String, Object>> list = departmentModels.parallelStream().map(m -> {
            List<String> nameList = new ArrayList<>();
            Map<String, Object> departmentCode = new HashMap<>();
            findChilderName(departmentModels, m, nameList);
            departmentCode.put("1", m.getId().toString());
            departmentCode.put("2", StringUtils.join(nameList, ">>"));
            return departmentCode;
        }).filter(f -> ObjectUtil.isNotEmpty(f)).toList();
        String fileName = "/exportDepartment/本系统用户组织编码" + LocalDateTime.now()+ ".xlsx";
        String fileType = "xlsx";
        String[] title = {"组织id", "组织名称"};
        File file = ExcelUtil.writer("机构列表", fileType, list, title);
        MultipartFile multipartFile = ExcelUtil.fileToMultipartFile(file);
        OSS client = null;
        client = ossPlugins.createClient();
        PutObjectRequest putObjectRequest = new PutObjectRequest(ossPlugins.ossConfig.getBucket(), ossPlugins.getFilePath(fileName), multipartFile.getInputStream());
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setObjectAcl(CannedAccessControlList.Private);
        LocalDate date = LocalDate.now().plusDays(1);
        long mili = date.atStartOfDay().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        metadata.setExpirationTime(new Date(mili));
        putObjectRequest.setMetadata(metadata);
        client.putObject(putObjectRequest);
        client = ossPlugins.createClient();
        file.delete();
        Date expiration = new Date(new Date().getTime() + 3600 * 1000);
        return client.generatePresignedUrl(ossPlugins.ossConfig.getBucket(), ossPlugins.getFilePath(fileName), expiration).toString().replace("http","https");
    }

    private void findChilderName(List<DepartmentModel> list, DepartmentModel model, List<String> nameList) {
        if (model == null) {
            return ;
        }
        if (model.getParentId() != null) {
            Optional<DepartmentModel> first = list.parallelStream().filter(f -> f.getId().equals(model.getParentId())).findFirst();
            DepartmentModel departmentModel = first.orElse(null);
            if (null == departmentModel) {
                return;
            }
            findChilderName(list, departmentModel, nameList);
        }
        nameList.add(model.getName());
    }
}
